package com.common.frame.permission

import android.Manifest
import android.app.AppOpsManager
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Binder
import android.os.Build
import android.os.Process
import android.provider.Settings
import androidx.annotation.RequiresApi
import androidx.core.content.PermissionChecker
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.LifecycleOwner
import com.common.frame.utils.Utils
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import java.lang.reflect.Field
import java.lang.reflect.Method

object PermissionHelper {

    const val FRAGMENT_TAG = "PermissionFragment"

    /**
     * 判断是否有某项权限
     */
    fun hasPermission(permission: String): Boolean {
        val perm = Utils.app.checkCallingOrSelfPermission(permission)
        return perm == PackageManager.PERMISSION_GRANTED
    }

    /**
     * 判断是否具备获取读写联系人权限的方法
     */
    fun hasContactsPermission(): Boolean {
        return hasPermission(Manifest.permission.READ_CONTACTS) && hasPermission(Manifest.permission.WRITE_CONTACTS)
    }

    /**
     * 判断是否具备获取通话记录权限的方法
     */
    fun hasCallPermission(): Boolean {
        return hasPermission(Manifest.permission.READ_CALL_LOG)
    }


    /**
     * 判断是否具备获取录音权限的方法
     */
    fun hasRecordPermission(): Boolean {
        return hasPermission(Manifest.permission.RECORD_AUDIO)
    }

    fun hasRecordContactsCallPermission(): Boolean {
        return hasRecordPermission() && hasCallPermission() && hasContactsPermission()
    }

    fun hasContactsAndCallPermission(): Boolean {
        return hasCallPermission() && hasContactsPermission()
    }

    //查看是否具有获取应用运行的权限
    fun hasUseConditionPermission(): Boolean {
        return try {
            val packageManager = Utils.app.packageManager
            val info = packageManager.getApplicationInfo( Utils.app.packageName, 0)
            val appOpsManager =  Utils.app.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager
            appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, info.uid, info.packageName) == AppOpsManager.MODE_ALLOWED;
        } catch ( e :Exception) {
            e.printStackTrace()
            false
        }
    }

    /**
     * 开启查看应用的权限
     */
    fun permissionLook(activity: FragmentActivity) {
        val pm: PackageManager = activity.packageManager
        //查看是否具有获取应用运行的权限
        val permission = PackageManager.PERMISSION_GRANTED ==
                pm.checkPermission("android.permission.SYSTEM_OVERLAY_WINDOW", activity.packageName)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            val intent = Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS)
            activity.startActivity(intent)
        }
    }

    fun request(
        context: LifecycleOwner,
        permission: String,
        listener: PermissionListener.() -> Unit
    ) {
        val callback = PermissionListener().also(listener)
        getInvisibleFragment(context).request(arrayOf(permission), callback)
    }

    fun request(
        context: LifecycleOwner,
        permission: Array<String>,
        listener: PermissionListener.() -> Unit
    ) {
        val callback = PermissionListener().also(listener)
        getInvisibleFragment(context).request(permission, callback)
    }

    private fun getInvisibleFragment(context: LifecycleOwner): PermissionFragment {
        val fragmentManager = getFragmentManager(context)
        val existedFragment = fragmentManager.findFragmentByTag(FRAGMENT_TAG)
        return if (existedFragment != null) {
            existedFragment as PermissionFragment
        } else {
            val invisibleFragment = PermissionFragment()
            fragmentManager.beginTransaction()
                .add(invisibleFragment, FRAGMENT_TAG)
                .commitNowAllowingStateLoss()
            invisibleFragment
        }
    }


    private fun getFragmentManager(context: LifecycleOwner): FragmentManager {
        return when (context) {
            is Fragment -> {
                context.childFragmentManager
            }
            else -> {
                (context as FragmentActivity).supportFragmentManager
            }
        }
    }


    /**
     * 是否开启了通知权限
     */
    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    fun isNotificationEnabled(context: Context): Boolean {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
            return false
        }
        val mAppOps =
            context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager
        val appInfo = context.applicationInfo
        val pkg = context.applicationContext.packageName
        val uid = appInfo.uid
        var appOpsClass: Class<*>? = null
        try {
            appOpsClass = Class.forName(AppOpsManager::class.java.name)
            val checkOpNoThrowMethod = appOpsClass.getMethod(
                "checkOpNoThrow",
                Integer.TYPE, Integer.TYPE, String::class.java
            )
            val opPostNotificationValue =
                appOpsClass.getDeclaredField("OP_POST_NOTIFICATION")
            val value = opPostNotificationValue[Int::class.java] as Int
            return checkOpNoThrowMethod.invoke(mAppOps, value, uid, pkg) as Int ==
                    AppOpsManager.MODE_ALLOWED
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return false
    }

    /**
     * 权限获取状态
     */
    fun getPermissionState(
        context: Context,
        permissionsTocheck: Array<String?>
    ): JSONArray {
        val array = JSONArray()
        for (i in permissionsTocheck.indices) {
            try {
                val `object` = JSONObject()
                `object`.put("checkTime", System.currentTimeMillis())
                `object`.put("permissionType", permissionsTocheck[i])
                if (isGranted(
                        context,
                        permissionsTocheck[i]
                    )
                ) {
                    `object`.put("isGranted", "GRANTED")
                } else {
                    `object`.put("isGranted", "REFUSED")
                }
                array.put(`object`)
            } catch (e: JSONException) {
                e.printStackTrace()
            }
        }
        return array
    }

    /**
     * 是否同意了某个权限
     */
    fun isGranted(ctx: Context, permission: String?): Boolean {
        return if (permission == null) {
            false
        } else Build.VERSION.SDK_INT < 23 || PermissionChecker.checkSelfPermission(
            ctx,
            permission
        ) == PermissionChecker.PERMISSION_GRANTED
    }

    /**
     * 权限是否全部获取
     */
    fun isGranted(
        ctx: Context,
        permissions: Array<String>?
    ): Boolean {
        if (permissions == null || permissions.isEmpty()) {
            return false
        }
        for (permission in permissions) {
            val isGranted =
                Build.VERSION.SDK_INT < 23 || PermissionChecker.checkSelfPermission(
                    ctx,
                    permission
                ) == PermissionChecker.PERMISSION_GRANTED
            if (!isGranted) {
                return false
            }
        }
        return true
    }


    /***
     * 检查悬浮窗开启权限
     * @param context
     * @return
     */
    fun checkFloatPermission(context: Context): Boolean {
        return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            try {
                var cls = Class.forName("android.content.Context")
                val declaredField: Field = cls.getDeclaredField("APP_OPS_SERVICE")
                declaredField.setAccessible(true)
                var obj: Any? = declaredField.get(cls) as? String ?: return false
                val str2 = obj as String
                obj = cls.getMethod("getSystemService", String::class.java).invoke(context, str2)
                cls = Class.forName("android.app.AppOpsManager")
                val declaredField2: Field = cls.getDeclaredField("MODE_ALLOWED")
                declaredField2.setAccessible(true)
                val checkOp: Method =
                    cls.getMethod("checkOp", Integer.TYPE, Integer.TYPE, String::class.java)
                val result =
                    checkOp.invoke(obj, 24, Binder.getCallingUid(), context.packageName) as Int
                result == declaredField2.getInt(cls)
            } catch (e: java.lang.Exception) {
                false
            }
        } else {
            if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O) {
                val appOpsMgr = context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager
                val mode = appOpsMgr.checkOpNoThrow(
                    "android:system_alert_window", Process.myUid(), context
                        .packageName
                )
                Settings.canDrawOverlays(context) || mode == AppOpsManager.MODE_ALLOWED || mode == AppOpsManager.MODE_IGNORED
            } else {
                Settings.canDrawOverlays(context)
            }
        }
    }

    class PermissionListener {
        var onAllAllowed: ((Boolean) -> Unit)? = null
        var onAllow: (() -> Unit)? = null
        var onRefuse: ((refused: List<String>) -> Unit)? = null

        fun onAllAllowed(action: (Boolean) -> Unit) {
            onAllAllowed = action
        }

        fun onAllow(action: () -> Unit) {
            onAllow = action
        }

        fun onRefuse(action: (refused: List<String>) -> Unit) {
            onRefuse = action
        }
    }

}